package ch.zbw.swt.sysventory.network.scan;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import ch.zbw.swt.sysventory.hibernate.entity.Computer;
import ch.zbw.swt.sysventory.hibernate.entity.Scan;
import ch.zbw.swt.sysventory.network.CalculateReachabelIpPart;
import ch.zbw.swt.sysventory.network.IPv4;
import ch.zbw.swt.sysventory.service.SqlDataWriter;

public class ScanMasterClass implements Runnable {

	private ArrayList<String> arrayListIpRange, arrayListReachable;
	private Scan scanVersion;
	private List<Computer> arrayListComputers;


	public ScanMasterClass(IPv4 startIP, IPv4 endIP) {

		this.arrayListReachable = new ArrayList<String>();
		this.arrayListComputers = new ArrayList<Computer>();
		this.arrayListIpRange = new ArrayList<String>();
		this.arrayListIpRange = startIP.getAvailableIPsbyIPs(startIP, endIP);

	}
	
	public ScanMasterClass(String ipToScan) {


		this.arrayListReachable = new ArrayList<String>();
		this.arrayListComputers = new ArrayList<Computer>();
		this.arrayListIpRange = new ArrayList<String>();
		this.arrayListIpRange.add(ipToScan);

	}

	private boolean pingBySocket(String ip) {
		boolean isReachable = false;
		Socket socket = new Socket();
		try {
			socket.connect(new InetSocketAddress(ip, 135), 150);
			isReachable = true;
		} catch (IOException e) {
			isReachable = false;
		}

		return isReachable;
	}

	public ArrayList<String> calculateReachableIpRangeFromStartAndEndIP() {
		for (String ip : arrayListIpRange) {
			if (pingBySocket(ip)) {
				arrayListReachable.add(ip);
			}
		}
		System.out.println(arrayListReachable);
		return arrayListReachable;
	}

	public void createThreadsforIpTest() throws ExecutionException {
		ExecutorService executor = Executors.newCachedThreadPool();
		List<Callable<CalculateReachabelIpPart>> tasks = new ArrayList<Callable<CalculateReachabelIpPart>>();

		for (String ip : arrayListIpRange) {

			tasks.add(new CalculateReachabelIpPart(ip));
		}

		try {
			List<Future<CalculateReachabelIpPart>> reachebelComputers = executor
					.invokeAll(tasks);
			for (Future<CalculateReachabelIpPart> ip : reachebelComputers) {
				if (ip.isDone() && ip.get().isIpReachebel()) {
					arrayListReachable.add(ip.get().getIp());
				}
			}
		} catch (InterruptedException e) {
			// to do
		}

	}

	public void createThreadsForComputerScans()  {
		ExecutorService executor = Executors.newCachedThreadPool();
		List<Callable<Computer>> tasks = new ArrayList<Callable<Computer>>();

		for (String ip : arrayListReachable) {
			tasks.add(new ScanComputer(ip));
		}

		try {

			List<Future<Computer>> computers = executor.invokeAll(tasks);
			for (Future<Computer> computer : computers) {

				try {
					if( computer.get()!= null){
						arrayListComputers.add(computer.get().getComputer());
					}
				} catch (ExecutionException e) {
					// TODO Auto-generated catch block
					System.out.println("hier I");
				}
			}
		} catch (InterruptedException e) {
			System.out.println("hier II");
		}
	}

	
	public String[][] createArray(){
		
		String[][] computers = new String[arrayListComputers.size()+1][arrayListComputers.size()+1];
		int i = 0;
		int j = 1;
		for(Computer computer : arrayListComputers){
			
			computers[i][i] = computer.getComputer().getDescription();
			computers[i][j] = computer.getComputer().getScanedHost();
			i++;
			j++;
		}
		
		return computers;
	}
	
	@Override
	public void run() {

		try {
			createThreadsforIpTest();
			createThreadsForComputerScans();
			createScanForDBWrite();
			storeScanToDB();
		} catch (ExecutionException e) {
			// to do
		}

	}

	private void storeScanToDB() {
		SqlDataWriter sqlWriter = new SqlDataWriter();
		sqlWriter.store(scanVersion);
	}

	private void createScanForDBWrite() {
		Date scanDatum = new Date();
		scanVersion = new Scan(scanDatum, "1");
		scanVersion.setComputers(arrayListComputers);
	}

}
